home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / docs / inter45e / intprint.c < prev    next >
C/C++ Source or Header  |  1995-03-25  |  58KB  |  2,203 lines

  1. /************************************************************************/
  2. /* INTPRINT.C by Ralf Brown.  Donated to the Public Domain.        */
  3. /* Please do not remove my name from any copies or derivatives.        */
  4. /************************************************************************/
  5. /* Program History:                            */
  6. /*   v1.00  4/23/89  initial public release                */
  7. /*             with 4/30/89 list                    */
  8. /*   v1.10  5/21/89  added -I and -f                    */
  9. /*   v1.11  1/6/90   fixed #endif's for compilers which don't handle    */
  10. /*             labels                        */
  11. /*   v1.20  6/8/90   added -r                        */
  12. /*   v1.30  7/14/90  added -b, tables now stay aligned on odd indents    */
  13. /*   v1.40  10/6/90  added -B based on changes by Naoto Kimura, -w    */
  14. /*   v1.40a 5/6/91   HP LaserJet II support by Russ Herman        */
  15. /*   v1.41  7/9/91   HP PCL support by P.J.Farley III            */
  16. /*   v2.00  9/1/91   modular printer definitions            */
  17. /*             printing multipart interrupt list            */
  18. /*   v2.01  2/9/92   fixed summary entry for non-numeric AX= and AH=    */
  19. /*             smarter page breaks                */
  20. /*   v2.02  2/18/92  bugfix & isxdigit suggested by Aaron West        */
  21. /*   v2.10  3/14/92  updated to handle extra flags in headings        */
  22. /*   v2.11  5/23/92  bugfix pointed out by Joe White            */
  23. /*   v2.20  6/12/92  added -F based on code by Richard Brittain        */
  24. /*             added -H and Panasonic printer def by Lewis Paper    */
  25. /*   v2.21  10/14/92 fixed error in -H/-r interaction            */
  26. /*             updated for new 'Bitmask of' section        */
  27. /*   v2.22   2/15/93 exclude Index: by default, -x to force inclusion    */
  28. /*             changed 'Bitmask of' to 'Bitfields for'        */
  29. /*   v2.23   5/24/93 fix to allow INT/AL= to appear correctly in summary*/
  30. /*   v2.24   7/15/93 -k and infinite-length pages by Bent Lynggaard    */
  31. /*   v3.00   6/4/94  -T, -V, and multi-file break section skipping    */
  32. /*             major speedups; checked for BC++3.1 compatibility    */
  33. /*   v3.01   6/11/94 bugfix: crashed with -l0 -L1 on lines >=80 chars   */
  34. /*   v3.02   1/7/95  bugfix by Mark Shapiro: garbage with -B -PHP_PCL    */
  35. /*   v3.03   1/14/95 changes for Borland C++ 4.x size minimization    */ 
  36. /*   v3.04   3/25/95 malloc/sbrk and other bugfixes                */
  37. /************************************************************************/
  38. /* Recompiling:                                */
  39. /*   Turbo C / Borland C++                        */
  40. /*    tcc -mt -lt -O -a -Z -p -k- intprint                */
  41. /*      bcc -mt -lt -a -d -O1agim -p intprint.c                */
  42. /*   Borland C++ 4.x (as .EXE, from John <tenthumbs@bix.com>)        */
  43. /*    bcc -ms -a -d -O1agim -p intprint.c noehs.lib            */
  44. /************************************************************************/
  45.  
  46. #include <ctype.h>
  47. #include <fcntl.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <sys/stat.h>        /* S_IREAD, S_IWRITE */
  52.  
  53. #define VERSION "3.04"
  54.  
  55. /***********************************************/
  56. /*    portability definitions               */
  57.  
  58. #define _other_        /* assume no system-specific match */
  59.  
  60. /*--------------------------------------------------*/
  61. /* first system: MS-DOS with Turbo/Borland C        */
  62.  
  63. #ifdef __TURBOC__
  64. #  define PROTOTYPES
  65. #  include <alloc.h>
  66. #  include <io.h>    /* open, close, read, lseek, etc. */
  67.    int _Cdecl isatty(int handle) ;
  68.  
  69.    /* definitions to reduce size of executable */
  70.    unsigned int _Cdecl _stklen = 1024 ;
  71.    #define close _close
  72.    #define read _read
  73.    #define write _write
  74.    void _Cdecl _setenvp(void) {} /* don't need environment--don't include it */
  75.    void *_Cdecl malloc(size_t size)
  76.      { void *x = sbrk(size) ; return (x==(char*)-1) ? 0 : x ; }
  77.    void _Cdecl free(void *var) { (void)var ; }
  78.    /* since our free() doesn't do anything, macro it out of existence */
  79.    #define free(p)
  80.  
  81.    #ifdef __BORLANDC__
  82.    void _Cdecl _setupio(void) {}
  83.    #pragma warn -eff
  84.    /* BC++ v3.1 sets __BORLANDC__ to 0x0410!! */
  85.    #if __BORLANDC__ >= 0x0400 && __BORLANDC__ != 0x0410
  86.    /* Changes by John Sasse to minimize executable size */
  87.    #if 1
  88.       /* the preferred way */
  89.       /* Borland claims they "might" stop supporting these functions. Right */
  90.       #define   _close(a)      _rtl_close(a)
  91.       #define   _creat(a,b)    _rtl_creat(a,b)
  92.       #define   _open(a,b)     _rtl_open(a,b)
  93.       #define   _read(a,b,c)   _rtl_read(a,b,c)
  94.       #define   _write(a,b,c)  _rtl_write(a,b,c)
  95.       #if __BORLANDC__ == 0x400
  96.       /* They forgot to change this in 4.00 only */
  97.       #undef    _read
  98.       #endif
  99.    #else
  100.       #pragma warn -obs    /* the easy way */
  101.    #endif /* 1 */
  102.    #endif /* __BORLANDC__ >= 0x400 */
  103.    #endif /* __BORLANDC__ */
  104.  
  105. #undef _other_
  106. #endif /* __TURBOC__ */
  107.  
  108. #ifdef __MSDOS__
  109. #  define LINE_TERMINATOR '\n'
  110. #endif
  111.  
  112. /*--------------------------------------------------*/
  113. /*   Gnu C compiler                                 */
  114.  
  115. #ifdef __GNUC__
  116. #define PROTOTYPES
  117. #define NEED_ITOA
  118. #define NEED_ULTOA
  119. #define NEED_STRUPR
  120. #define NEED_STRNICMP
  121.  
  122. #undef _other_
  123. #endif /* __GNUC__ */
  124.  
  125. /*--------------------------------------------------*/
  126. /*  generic Unix definitions                        */
  127.  
  128. #ifdef unix
  129. #  include <sys/unistd.h>    /* open, close, read, lseek, etc. */
  130. #  include <sysent.h>        /* open, close, read, lseek, etc. */
  131. extern int isatty(int) ;
  132. #  define LINE_TERMINATOR '\n'
  133. #endif
  134.  
  135.  
  136. /*--------------------------------------------------*/
  137. /*  any other system                                */
  138.  
  139. #ifdef _other_
  140. /* unknown compiler/system, so set configuration #defines */
  141. #if 0  /* set to 1 if compiler supports ANSI-style prototypes, 0 otherwise */
  142. #define PROTOTYPES
  143. #endif
  144. #if 1  /* set to 0 if library contains strnicmp(), 1 otherwise */
  145. #define NEED_STRNICMP
  146. #endif
  147. #if 1  /* set to 0 if library contains isxdigit(), 1 otherwise */
  148. #define NEED_ISXDIGIT
  149. #endif
  150. #if 1  /* set to 0 if library contains strupr(), 1 otherwise */
  151. #define NEED_STRUPR
  152. #endif
  153. #if 1  /* set to 0 if library contains three-arg itoa(), 1 otherwise */
  154. #define NEED_ITOA
  155. #endif
  156. #if 1  /* set to 0 if library contains three-arg ultoa(), 1 otherwise */
  157. #define NEED_ULTOA
  158. #endif
  159.  
  160. #endif /* _other_ */
  161.  
  162. /*--------------------------------------------------*/
  163.  
  164. /* the last character of the line termination sequence, i.e. '\n' for CRLF */
  165. /* and LF, '\r' if your system uses CR or LFCR */
  166. #ifndef LINE_TERMINATOR
  167. #define LINE_TERMINATOR '\n'
  168. #endif /* LINE_TERMINATOR */
  169.  
  170. /*--------------------------------------------------*/
  171. /*  catchall for macros which might not be defined  */
  172.  
  173. #ifndef O_BINARY
  174. #  define O_BINARY 0
  175. #endif
  176.  
  177. #ifndef _Cdecl
  178. #  define _Cdecl
  179. #endif
  180.  
  181. /***********************************************/
  182.  
  183. #ifndef FALSE
  184. #define FALSE 0
  185. #endif
  186. #ifndef TRUE
  187. #define TRUE !FALSE
  188. #endif
  189.  
  190. /***********************************************/
  191.  
  192. #define MAXLINE 82   /* at most 80 chars per line (plus CR and newline) */
  193. #define MAXPAGE 200  /* at most 200 lines per page */
  194.  
  195. #define lengthof(x) (sizeof(x)/sizeof(x[0]))
  196.  
  197. #define divider_line(line) (line[0] == '-' && memcmp(line+1,"-------",7) == 0)
  198. #ifdef __MSDOS__
  199. #define start_of_entry(s) (((int*)s)[0]==(256*'N'+'I')&&((int*)s)[1]==(256*' '+'T'))
  200. #define index_line(l) \
  201.   (((int*)l)[0]==(256*'n'+'I')&&((int*)l)[1]==(256*'e'+'d')&& \
  202.    ((int*)l)[2]==(256*':'+'x'))
  203. #else
  204. #define start_of_entry(s) (memcmp(s,"INT ",4) == 0)
  205. #define index_line(line) (line[0] == 'I' && memcmp(line+1,"ndex:",5) == 0)
  206. #endif
  207. #define section_start(line) is_keyword(line,section_start_keys,lengthof(section_start_keys))
  208. #define start_of_table(line) (is_keyword(line,table_start_keys,lengthof(table_start_keys)))
  209.    
  210. #define section_file_start(s) (s[0] == '-' && memcmp(s+1,"-------!---Section",18) == 0)
  211.  
  212.  
  213. /***********************************************/
  214. /*    stub functions to reduce executable size */
  215. /***********************************************/
  216.  
  217. #ifdef __BORLANDC__
  218. /* Changes by John Sasse */
  219. /* BC++ v3.1 sets __BORLANDC__ to 0x0410!!  */
  220. #if __BORLANDC__ >= 0x0400 && __BORLANDC__ != 0x0410
  221. /*      Everything within this conditional may be placed in
  222.  *      a separate source file if desired.
  223.  */
  224.  
  225. /* stack overflow checking can never be allowed inside
  226.    the run-time library */
  227. #pragma option -N-
  228.  
  229. #include <errno.h>
  230. /* the next 3 include files are necessary only if this
  231.    is compiled as a separate file */
  232. #if 0
  233. #include <io.h>
  234. #include <stdlib.h>
  235. #include <string.h>
  236. #endif
  237.  
  238. /* declarations */
  239. void _Cdecl      __ErrorMessage (const char *__message);
  240. int  pascal near __IOerror (int  _doserror_);
  241. int  pascal near __DOSerror (int  _doserror_);
  242. void _Cdecl      _abort (void);
  243.  
  244.  
  245. /* may be referenced by a lot of things */
  246. int _Cdecl _doserrno = 0;
  247.  
  248. /*
  249.     The _rtl_* functions all call __IOError which originally
  250.     referenced sys_nerr and sys_errlist. Unfortunately, the
  251.     source file for these also contains perror which calls
  252.     fputs. Hence you get lots of extra code.
  253.     This is a very minimal replacement.
  254. */
  255. int pascal near __IOerror(int _doserror_)
  256. {
  257. /* if _doserror_ is < 0, it might be a System V error.
  258.    we don't care */
  259.     _doserrno = (_doserror_ < 0) ? (-1) : _doserror_;
  260.     errno = EIO;        /* a default value */
  261.     return (-1);
  262. }
  263.  
  264. /* __DOSerror and __IOerror are in the same source file.
  265.    This may not actually be called. Better safe ...
  266. */
  267. #if 1
  268. int pascal near __DOSerror(int _doserror_)
  269. {
  270.     __IOerror(_doserror_);
  271.     return (_doserror_);
  272. }
  273. #endif
  274.  
  275. /*
  276.    The startup code, among others, references _setargv which
  277.    references abort. The run-time library version says "raise
  278.    (SIGABRT)", bringing in a lot of unnecessary code.
  279. */
  280. void _Cdecl abort (void)
  281. {
  282.     _abort ();
  283. }
  284.  
  285. /* necessary to avoid referencing _streams */
  286. #if 1
  287. #define STDERR      2
  288.  
  289. void _Cdecl __ErrorMessage(const char *msg)
  290. {
  291.     _rtl_write(STDERR, msg, strlen(msg));
  292. }
  293. #endif
  294.  
  295. /* restore command line state; note the "." */
  296. #pragma option -N.
  297.  
  298. #endif  /* __BORLANDC__ >= 0x400 */
  299. #endif  /* __BORLANDC__ */
  300.  
  301. /***********************************************/
  302. /*    replacement file I/O function macros     */
  303. /***********************************************/
  304.  
  305. typedef struct
  306.    {
  307.    int fd ;
  308.    int buf_maxsize ;
  309.    char *buf ;
  310.    unsigned long bufoffset ;
  311.    int bufsize ;
  312.    int bufpos ;
  313.    int write ;             /* file is output file if nonzero */
  314.    } IP_FILE ;
  315.  
  316. #define ip_putc(c,fp) \
  317.   ((fp)->buf[fp->bufpos++]=(c),\
  318.    ((fp)->bufpos>=(fp)->buf_maxsize&&ip_flush(fp)==-1)?-1:0)
  319.  
  320. /* output the indicated counted string to the given file */
  321. #define ip_putcstr(s,fp) ip_write((s)->str,(s)->len,fp)
  322. /* output the given string literal to the indicated file */
  323. #define ip_putlit(s,fp) ip_write((s),sizeof(s)-1,fp)
  324. /* output the given string variable to the indicated file */
  325. #define ip_puts(s, fp) ip_write(s,strlen(s),fp)
  326.  
  327. #ifdef __MSDOS__
  328. #define newline(fp) ip_write("\r\n",2,fp)
  329. #else
  330. #define newline(fp) ip_putc('\n',fp)
  331. #endif
  332.  
  333. /***********************************************/
  334.  
  335. typedef struct             /* a counted string */
  336.    {
  337.    int len ;             /* the string's length */
  338.    char *str ;             /* the actual contents of the string */
  339.    } cstr ;
  340.  
  341. #define CSTR(s) { sizeof(s)-1, (s) }  /* for defining a counted string literal */
  342. #define cstrlen(s) ((s)->len)     /* how long is the counted string? */
  343.  
  344. typedef struct
  345.    {
  346.    char *name ;            /* for selecting the appropriate printer */
  347.    cstr init1, init2 ;        /* initialization strings */
  348.    cstr marginl, marginc, marginr ; /* margins: duplex even, non-duplex, duplex odd */
  349.    cstr duplex_on ;        /* turn on duplex mode */
  350.    cstr term1, term2 ;        /* cleanup strings */
  351.    cstr bold_on, bold_off ;    /* boldface on/off */
  352.    int indent ;            /* how many extra spaces to indent */
  353.    int lines_per_page ;        /* how many lines to print on each page */
  354.    int page_length ;        /* how many lines on each page */
  355.    int page_width ;        /* how many printable columns per line? */
  356. #ifdef PROTOTYPES
  357.    void (*put_line)(IP_FILE *,int) ;/* function to call to print out divider line */
  358.    void (*set_typeface)(IP_FILE *,char *) ;
  359. #else
  360.    void (*put_line)() ;        /* function to call to print out divider line */
  361.    void (*set_typeface)() ;
  362. #endif /* PROTOTYPES */
  363.    int *flag ;            /* flag to set when using this printer definition */
  364.    } PRINTER_DEF ;
  365.  
  366. typedef struct filter_list
  367.    {
  368.    struct filter_list *next ;
  369.    char str[1] ;        /* will allocate enough for actual string */
  370.    } FILT_LIST ;
  371.  
  372. typedef struct
  373.    {
  374.    int part ;
  375.    int first_on_page ; /* TRUE if a new entry starts at the top of the page */
  376.    char desc[24] ;
  377.    int len ;
  378.    } HEADER ;
  379.  
  380. typedef struct
  381.    {
  382. /*   char *name ;*/
  383.    char name[14] ;
  384.    int length ;
  385.    } KEYWORDS ;
  386.  
  387. /***********************************************/
  388.  
  389. #ifdef PROTOTYPES
  390. void usage(void) ;
  391. void fatal(char *msg) ;
  392. void warning(char *msg) ;
  393. int unwanted_section(char *buf) ;
  394. IP_FILE *ip_fdopen(int fd,char *buf,int bufsiz, int maxsiz, int write) ;
  395. IP_FILE *ip_open_write(char *name, int trunc, char *buf, int bufsiz) ;
  396. IP_FILE *ip_open_read(char *name, char *buf, int bufsiz) ;
  397. int ip_close(IP_FILE *fp) ;
  398. unsigned long ip_fgets(char *buf, int max, IP_FILE *fp) ;
  399. int ip_write(char *buf, int count, IP_FILE *fp) ;
  400. int ip_flush(IP_FILE *fp) ;
  401. void get_raw_line(char *buf) ;
  402. void get_line(char *buf) ;
  403. void indent_to(int where,IP_FILE *fp) ;
  404. void put_line(IP_FILE *fp, int len) ;
  405. void HPPCL_put_line(IP_FILE *fp, int len) ;
  406. void HPPCL_set_typeface(IP_FILE *fp,char *typeface) ;
  407. int is_keyword(char *s, KEYWORDS *keys, unsigned int numkeys) ;
  408. void output_line(char *line,IP_FILE *fp) ;
  409. void fill_buffer(int lines, int lines_per_page) ;
  410. int find_page_break(int lines) ;
  411. int summarize(int line, int pages_printed) ;
  412. void start_format(char *line) ;
  413. void write_summary_header(IP_FILE *fp, char *title, int offsets, int tables) ;
  414. void show_offset(int line,IP_FILE *fp) ;
  415. void add_table(int i) ;
  416. FILT_LIST *add_filter_info(FILT_LIST *list,char *str) ;
  417. void build_filter_lists(char *file) ;
  418. int make_description(char *desc,int line) ;
  419. char *determine_heading(int last) ;
  420. void print_buffer(int last,int body_lines,int lines_per_page,int total_lines,
  421.           int use_FF) ;
  422. void select_printer(char *name) ;
  423. void display_printers(void) ;
  424. static void reset_printer_and_close(IP_FILE *fp) ;
  425. int _Cdecl main(int argc, char **argv) ;
  426. #else
  427. void put_line() ;
  428. void HPPCL_put_line() ;
  429. void HPPCL_set_typeface() ;
  430. void show_offset() ;
  431. #endif /* PROTOTYPES */
  432.  
  433. /***********************************************/
  434. /*    I/O buffers                   */
  435. /***********************************************/
  436.  
  437. char stderr_buf[256] ;
  438. char filter_buf[256] ;
  439. char infile_buf[8192] ;
  440. char outfile_buf[8192] ;
  441. char summary_buf[4096] ;
  442. char formats_buf[3072] ;
  443. char tables_buf[3072] ;
  444.  
  445. /***********************************************/
  446.  
  447. IP_FILE *err ;
  448. IP_FILE *infile ;
  449. IP_FILE *outfile ;
  450. char *input_file ;
  451. int input_file_namelen ;
  452.  
  453. char buffer[MAXPAGE][MAXLINE] ;
  454. unsigned long line_offsets[MAXPAGE] ;
  455. char num[6] ;
  456. int need_summary ;
  457. char summary_line[2*MAXLINE] ;
  458. int summary_line_len ;
  459.  
  460. int pages_printed = 0 ;
  461. int page_width = 0 ;        /* page width in characters, 0 = use prtdef */
  462. int indent = 0 ;            /* number of columns to indent lines */
  463. char *indent_string = NULL ;    /* what to add at start of line to indent */
  464. int indent_len = 0 ;            /* length of indent_string */
  465. int widow_length = 8 ;        /* number of lines to scan for good place to break */
  466. int page_numbers = FALSE ;    /* add page numbers to bottom of page? */
  467. int multi_file = FALSE ;    /* printing multipart interrupt list? */
  468. int out_of_files = FALSE ;    /* hit end of last file for multipart printing? */
  469. int do_summary = FALSE ;    /* create a one-line-per-call summary? */
  470. int do_tables = FALSE ;        /* create a one-line-per-table index? */
  471. int do_formats = FALSE ;    /* create a separate file with data structures? */
  472. int do_filter = FALSE ;        /* using a filtering file? */
  473. int do_headers = FALSE ;    /* add page headings? */
  474. int include_index_lines = FALSE ;
  475. int IBM_chars = FALSE ;        /* printer can handle IBM graphics characters */
  476. int boldface = FALSE ;        /* boldface titles and Return:/Notes: ? */
  477. int printer_bold = FALSE ;    /* boldface using printer control sequences? */
  478. int echo_format = FALSE ;
  479. int duplex = FALSE ;
  480. int HPPCL_mode = FALSE ;
  481. int show_offsets = FALSE ;
  482. int keep_divider_lines = FALSE ;
  483. IP_FILE *summary ;
  484. IP_FILE *tables ;
  485. IP_FILE *formats ;
  486. PRINTER_DEF *printer = NULL ;
  487.  
  488. unsigned long current_line_offset = 0 ;
  489. unsigned long offset_adjust = 0 ;
  490.  
  491. unsigned int first_page = 0 ;
  492. unsigned int last_page = ~0 ;
  493.  
  494. int prev_table = 0 ;
  495.  
  496. FILT_LIST *includes = NULL ;
  497. FILT_LIST *excludes = NULL ;
  498.  
  499. HEADER header_first = { 0, FALSE, "" } ;
  500. HEADER header_last = { 0, FALSE, "" } ;
  501.  
  502. /***********************************************/
  503.  
  504. PRINTER_DEF printers[] =
  505.    {
  506.      { "default",
  507.        CSTR(""), CSTR(""),
  508.        CSTR(""), CSTR(""), CSTR(""),
  509.        CSTR(""),
  510.        CSTR(""), CSTR(""),
  511.        CSTR(""), CSTR(""),
  512.        -1,
  513.        60,
  514.        0,
  515.        79,
  516.        put_line,
  517.        NULL,
  518.        NULL,
  519.      },
  520.      { "Epson FX80, 12 cpi",
  521.        CSTR("\033M"), CSTR(""),
  522.        CSTR("\033l\004"), CSTR("\033l\007"), CSTR("\033l\014"),
  523.        CSTR(""),
  524.        CSTR("\033P"), CSTR("\033l\000"),
  525.        CSTR("\033E"), CSTR("\033F"),
  526.        0,
  527.        60,
  528.        0,
  529.        87,    /* 96 - left margin - 1 right margin */
  530.        put_line,
  531.        NULL,
  532.        NULL,
  533.      },
  534.      { "Panasonic KX-P1124i / 10 cpi Epson",
  535.        CSTR(""), CSTR(""),
  536.        CSTR(""), CSTR(""), CSTR(""),
  537.        CSTR(""),
  538.        CSTR(""), CSTR(""),
  539.        CSTR("\033E"), CSTR("\033F"),
  540.        -1,
  541.        60,
  542.        0,
  543.        79,
  544.        put_line,
  545.        NULL,
  546.        NULL,
  547.      },
  548.      { "HP PCL",
  549.        CSTR("\033(8U"), CSTR(""),
  550.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  551.        CSTR("\033&l1S"),
  552.        CSTR("\033E"), CSTR(""),
  553.        CSTR("\033(s3B"), CSTR("\033(s0B"),
  554.        0,
  555.        69,
  556.        0,
  557.        87,    /* 96 - left margin - 1 right margin */
  558.        HPPCL_put_line,
  559.        HPPCL_set_typeface,
  560.        &HPPCL_mode,
  561.      },
  562. #define HPPCL_FONT_ON_A "\033(s0p12h10v0s0b"
  563. /* HP PCL4/5 Font select: Roman-8;Upright12Pitch10PointMediumWeight */
  564. #define HPPCL_FONT_ON_B "T\033&l6.8571C"
  565. /* HP PCL4/5 Font select: End typeface select;VMI=7LPI: (48/7)-48th's inches*/
  566. #define HPPCL_IBM_LN_A    "\033&f0S\033*p-15Y\033*c"
  567. /* HP PCL4/5 IBM Line:    Push Pos;Up 15/720";Hor.Rule ???/300ths" long */
  568. #define HPPCL_IBM_LN_B    "a3b0P\033&f1S"
  569. /* HP PCL4/5 IBM Line:     3/300ths" high,Print rule;Pop Position */
  570.      { "LaserJet II",
  571.        CSTR("\033(10U"),CSTR(""),
  572.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  573.        CSTR(""),
  574.        CSTR("\033E"),CSTR(""),
  575.        CSTR("\033(s3B"),CSTR("\033(s0B"),
  576.        0,
  577.        54,
  578.        60,
  579.        79,
  580.        put_line,
  581.        NULL,
  582.        &IBM_chars,
  583.      },
  584.    } ;
  585. #define NUM_PRINTERS lengthof(printers)
  586.  
  587. /***********************************************/
  588.  
  589. #define KEYWORD_ENTRY(s) { s, sizeof(s)-1 }
  590.  
  591. KEYWORDS section_start_keys[] =
  592.    {
  593.     KEYWORD_ENTRY("BUG:"),
  594.     KEYWORD_ENTRY("BUGS:"),
  595.     KEYWORD_ENTRY("Desc:"),
  596.     KEYWORD_ENTRY("Index:"),
  597.     KEYWORD_ENTRY("Note:"),
  598.     KEYWORD_ENTRY("Notes:"),
  599.     KEYWORD_ENTRY("Program:"),
  600.     KEYWORD_ENTRY("Range:"),
  601.     KEYWORD_ENTRY("Return:"),
  602.     KEYWORD_ENTRY("SeeAlso:"),
  603.    } ;
  604.  
  605. KEYWORDS table_start_keys[] =
  606.    {
  607.     KEYWORD_ENTRY("Bitfields "),
  608.     KEYWORD_ENTRY("Call "),
  609.     KEYWORD_ENTRY("Format "),
  610.     KEYWORD_ENTRY("Values "),
  611.    } ;
  612.  
  613. /***********************************************/
  614.  
  615. #ifdef isxdigit
  616. #undef NEED_ISXDIGIT
  617. #endif
  618.  
  619. #ifdef NEED_STRNICMP
  620. #ifdef PROTOTYPES
  621. int strnicmp(char *s1,char *s2,unsigned int len) ;
  622. #endif
  623. int strnicmp(s1,s2,len)
  624. char *s1,*s2 ;
  625. unsigned int len ;
  626. {
  627.    char c1, c2 ;
  628.  
  629.    while (*s1 && *s2 && len > 0)
  630.       {
  631.       len-- ;
  632.       c1 = (islower(*s1) ? toupper(*s1) : *s1) ;
  633.       c2 = (islower(*s2) ? toupper(*s2) : *s2) ;
  634.       if (c1 != c2 || len == 0)     /* mismatch or substrings exhausted? */
  635.      return (c1 - c2) ;
  636.       s1++ ;
  637.       s2++ ;
  638.       }
  639.    return 0 ;  /* strings match exactly on first 'len' characters */
  640. }
  641. #endif /* NEED_STRNICMP */
  642.  
  643. #ifdef NEED_STRUPR
  644. #ifdef PROTOTYPES
  645. char *strupr(char *s) ;
  646. #endif
  647. char *strupr(s)
  648. char *s ;
  649. {
  650.    char *orig_s = s ;
  651.    char c ;
  652.    
  653.    if (s)
  654.       while (*s)
  655.      {
  656.      c = *s ;      
  657.      *s++ = (islower(c) ? toupper(c) : c) ;
  658.      }
  659.    return orig_s ;
  660. }
  661. #endif /* NEED_STRUPR */
  662.  
  663. #ifdef NEED_ISXDIGIT
  664. #ifdef PROTOTYPES
  665. int isxdigit(int c) ;
  666. #endif
  667. int isxdigit(c)
  668. int c ;
  669. {
  670.    return isdigit(c) || (memchr("ABCDEFabcdef",c,12) != NULL) ;
  671. }
  672. #endif /* NEED_ISXDIGIT */
  673.  
  674. #ifdef NEED_ITOA
  675. #ifdef PROTOTYPES
  676. char *itoa(int num,char *buf,int radix) ;
  677. #endif
  678. char *itoa(num,buf,radix)   /* not everybody has the same itoa() as TurboC */
  679. int num ;            /* minimal implementation */
  680. char *buf ;
  681. int radix ;
  682. {
  683.    int count = 0 ;
  684.    int i ; 
  685.    char tmp ;
  686.  
  687.    do {
  688.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  689.       num /= radix ;
  690.    } while (num) ;
  691.    buf[count] = '\0' ;
  692.    if (count > 1)
  693.       for (i = 0 ; i < count / 2 ; i++)
  694.      {
  695.      tmp = buf[i] ;
  696.      buf[i] = buf[count-i-1] ;
  697.      buf[count-i-1] = tmp ;
  698.      }
  699.    return buf ;
  700. }
  701. #endif /* NEED_ITOA */
  702.  
  703. #ifdef NEED_ULTOA
  704. #ifdef PROTOTYPES
  705. char *ultoa(unsigned long num,char *buf,int radix) ;
  706. #endif
  707. char *ultoa(num,buf,radix)   /* not everybody has the same ultoa() as TurboC */
  708. unsigned long num ;         /* minimal implementation */
  709. char *buf ;
  710. int radix ;
  711. {
  712.    int count = 0 ;
  713.    int i ; 
  714.    char tmp ;
  715.  
  716.    do {
  717.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  718.       num /= radix ;
  719.    } while (num) ;
  720.    buf[count] = '\0' ;
  721.    if (count > 1)
  722.       for (i = 0 ; i < count / 2 ; i++)
  723.      {
  724.      tmp = buf[i] ;
  725.      buf[i] = buf[count-i-1] ;
  726.      buf[count-i-1] = tmp ;
  727.      }
  728.    return buf ;
  729. }
  730. #endif /* NEED_ULTOA */
  731.  
  732. /***********************************************/
  733.  
  734. void usage()
  735. {
  736.    ip_putlit("\
  737. Usage: intprint [options] intlist [>|>>]output\r\n\
  738. Options:\r\n\
  739. Filtering:\t-Ffile\tprint only entries matching filtering info in 'file'\r\n\
  740. \t\t-k\tkeep original divider lines\r\n\
  741. \t\t-rN:M\tprint only pages N through M\r\n\
  742. \t\t-x\tinclude Index: lines in formatted output\r\n\
  743. Formatting:\t-b\tboldface headings\t-B\tbold with control codes\r\n\
  744. \t\t-d\t(duplex) print even/odd pages with different indents\r\n\
  745. \t\t-e\t(elite) 96 chars/line\t-tN\tselect typeface N\r\n\
  746. Pagination:\t-H\tadd page headers\t-iN\tindent N spaces\r\n\
  747. \t\t-p\tnumber pages\t\t-nN\tN pages already printed\r\n\
  748. \t\t-wN\twidow lines control\r\n\
  749. \t\t-lN\tprint length\t\t-LN\ttotal page length\r\n\
  750. \t\t\t(0 = infinite)\t(use linefeeds if > #lines printed)\r\n\
  751. Printer:\t-I\tIBM graphics characters\r\n\
  752. \t\t-Pname\tassume printer 'name'\t-P?\tlist printers\r\n\
  753. Summaries:\t-ffile\tdata structure formats\t-sfile\tINT calls\r\n\
  754. \t\t-Tfile\tlist tables\r\n\
  755. Misc:\t\t-m\tprocess multiple parts\t-V\tmake INTERVUE summary\r\n\
  756. "
  757.     ,err) ;
  758.    ip_flush(err) ;
  759.    exit(1) ;
  760. }
  761.  
  762. /***********************************************/
  763.  
  764. void fatal(msg)
  765. char *msg ;
  766. {
  767.    ip_putlit("UNRECOVERABLE ERROR:",err) ;
  768.    newline(err) ;
  769.    ip_puts(msg,err) ;
  770.    newline(err) ;
  771.    ip_flush(err) ;
  772.    exit(1) ;
  773. }
  774.  
  775. /***********************************************/
  776.  
  777. void warning(msg)
  778. char *msg ;
  779. {
  780.    ip_putlit("Warning: ",err) ;
  781.    ip_puts(msg,err) ;
  782.    newline(err) ;
  783. }
  784.  
  785. /***********************************************/
  786.  
  787. IP_FILE *ip_fdopen(fd,buf,bufsiz,maxsiz,write)
  788. int fd ;
  789. char *buf ;
  790. int bufsiz, maxsiz, write ;
  791. {
  792.    IP_FILE *fp = (IP_FILE *)malloc(sizeof(IP_FILE)) ;
  793.    
  794.    if (fp)
  795.       {
  796.       fp->fd = fd ;
  797.       fp->buf = buf ;
  798.       fp->bufsize = bufsiz ;
  799.       fp->buf_maxsize = maxsiz ;
  800.       fp->bufpos = 0 ;
  801.       fp->bufoffset = 0 ;
  802.       fp->write = write ;
  803.       }
  804.    return fp ;
  805. }
  806.  
  807. /***********************************************/
  808.  
  809. IP_FILE *ip_open_write(name,trunc,buf,bufsiz)
  810. char *name ;
  811. char *buf ;
  812. int trunc ;
  813. int bufsiz ;
  814. {
  815.    int fd ;
  816.    
  817.    if (name && *name == '\0')
  818.       fd = 1 ;    /* open stdout */
  819.    else
  820.       {
  821. #ifdef __TURBOC__
  822.       if (trunc)
  823.      fd = _creat(name,0) ;     /* create with no attribute bits sets */
  824.       else
  825.      fd = _open(name,O_WRONLY) ;
  826. #else
  827.       if (trunc) trunc = O_TRUNC ;
  828.       fd = open(name,O_WRONLY|O_BINARY|O_CREAT|trunc,S_IREAD|S_IWRITE) ;
  829. #endif
  830.       if (fd == -1)
  831.      return 0 ;
  832.       if (!trunc)
  833.      lseek(fd,0L,SEEK_END) ;
  834.       }
  835.    return ip_fdopen(fd,buf,bufsiz,bufsiz,1) ;
  836. }
  837.  
  838. /***********************************************/
  839.  
  840. IP_FILE *ip_open_read(name,buf,bufsiz)
  841. char *name ;
  842. char *buf ;
  843. int bufsiz ;
  844. {
  845.    int fd, siz ;
  846.  
  847. #ifdef __TURBOC__
  848.    if ((fd = _open(name,O_RDONLY)) != -1)
  849. #else
  850.    if ((fd = open(name,O_RDONLY | O_BINARY,0)) != -1)
  851. #endif
  852.       {
  853.       siz = read(fd,buf,bufsiz) ;
  854.       if (siz == -1)
  855.      return 0 ;
  856.       return ip_fdopen(fd,buf,siz,bufsiz,0) ;
  857.       }
  858.    else
  859.       return 0 ;
  860. }
  861.  
  862. /***********************************************/
  863.  
  864. int ip_flush(fp)
  865. IP_FILE *fp ;
  866. {
  867.    if (fp->write && fp->bufpos)
  868.       {
  869.       if (fp->bufpos > fp->buf_maxsize)
  870.      fp->bufpos = fp->buf_maxsize ;
  871.       if (write(fp->fd,fp->buf,fp->bufpos) == -1)
  872.      return -1 ;
  873.       fp->bufpos = 0 ;
  874.       }
  875.    return 0 ;       
  876. }
  877.  
  878. /***********************************************/
  879.  
  880. int ip_close(fp)
  881. IP_FILE *fp ;
  882. {
  883.    if (ip_flush(fp) == -1 || close(fp->fd) == -1)
  884.       return -1 ;
  885.    free(fp) ;
  886.    return 0 ;
  887. }
  888.  
  889. /***********************************************/
  890.  
  891. unsigned long ip_fgets(buf, max, fp)
  892. char *buf ;
  893. int max ;
  894. IP_FILE *fp ;
  895. {
  896.    unsigned long line_offset = fp->bufoffset + fp->bufpos ;
  897.    char *end ;
  898.    int len ;
  899.    int new_bufpos ;
  900.    char *fpbuf = fp->buf ;
  901.    int bufpos = fp->bufpos ;
  902.    
  903.    --max ;
  904.    if (bufpos + max < fp->bufsize)
  905.       {
  906.       end = (char *)memchr(fpbuf+bufpos,LINE_TERMINATOR,max) ;
  907.       if (end)
  908.      {
  909.      new_bufpos = (end-fpbuf) ;
  910.      len = new_bufpos++ - bufpos ;
  911.      /* eradicate rest of multi-character line terminator */
  912.      while (len > 0 && fpbuf[bufpos+len-1] <= ' ')
  913.         len-- ;
  914.      }
  915.       else
  916.      {
  917.      len = max ;
  918.      new_bufpos = bufpos + len ;
  919.      }
  920.       if (len)
  921.      memcpy(buf,fpbuf+bufpos,len) ;
  922.       buf[len] = '\0' ;
  923.       bufpos = new_bufpos ;
  924.       }
  925.    else
  926.       {
  927.       for (len = 1 ; len <= max ; len++)
  928.      {
  929.      *buf = fpbuf[bufpos++] ;
  930.      if (bufpos >= fp->bufsize)
  931.         {
  932.         if (fp->bufsize < fp->buf_maxsize)
  933.            {
  934.            fp->bufsize = bufpos = 0 ;
  935.            fpbuf[0] = '\0' ;  /* dummy value to ensure empty string */
  936.            }
  937.         else
  938.            {
  939.            fp->bufoffset += fp->buf_maxsize ;
  940.            fp->bufsize = read(fp->fd,fpbuf,fp->buf_maxsize) ;
  941.            bufpos = 0 ;
  942.            }
  943.         if (fp->bufsize <= 0)
  944.            {
  945.            line_offset = (unsigned long)-1 ; /* signal end of file */
  946.            if (*buf != LINE_TERMINATOR)
  947.           *buf++ = LINE_TERMINATOR;
  948.            break ;
  949.            }
  950.         }
  951.      if (*buf == LINE_TERMINATOR)
  952.         break ;
  953.      else
  954.         buf++ ;
  955.      }
  956.       if (len > max)       /* did we overflow before hitting EOL? */
  957.      *buf = '\0' ;       /* if yes, plug in the terminator */
  958.       else
  959.      /* eradicate rest of multi-character line terminator */
  960.      while (len-- > 0 && *buf <= ' ')
  961.         *buf-- = '\0' ;
  962.       }
  963.    fp->bufpos = bufpos ;
  964.    return line_offset ;
  965. }
  966.  
  967. /***********************************************/
  968.  
  969. int ip_write(buf, count, fp)
  970. char *buf ;
  971. int count ;
  972. IP_FILE *fp ;
  973. {
  974.    if (fp->bufpos + count < fp->buf_maxsize)
  975.       {
  976.       memcpy(fp->buf+fp->bufpos,buf,count) ;
  977.       fp->bufpos += count ;
  978.       }
  979.    else
  980.       while (count > 0)
  981.      {
  982.      int partial = fp->buf_maxsize - fp->bufpos ;
  983.  
  984.      if (count < partial)
  985.         partial = count ;
  986.      memcpy(fp->buf+fp->bufpos,buf,partial) ;
  987.      buf += partial ;
  988.      fp->bufpos += partial ;
  989.      count -= partial ;
  990.      if (fp->bufpos >= fp->buf_maxsize && ip_flush(fp) == -1)
  991.            return -1 ;
  992.      }
  993.    return 0 ;
  994. }
  995.  
  996. /***********************************************/
  997.  
  998. #define indent_line(fp) if(indent_string)ip_write(indent_string,indent_len,fp)
  999.  
  1000. /***********************************************/
  1001.  
  1002. void indent_to(where,fp)
  1003. int where ;
  1004. IP_FILE *fp ;
  1005. {
  1006.    where += indent ;
  1007.    while (where >= 8)
  1008.       {
  1009.       ip_putc('\t',fp) ;
  1010.       where -= 8 ;
  1011.       }
  1012.    if (where)
  1013.       ip_write("        ",where,fp) ;
  1014. }
  1015.  
  1016. /***********************************************/
  1017.  
  1018. void put_line(fp,len)
  1019. IP_FILE *fp ;
  1020. int len ;
  1021. {
  1022.    static char line[8] = { 196, 196, 196, 196, 196, 196, 196, 196 } ;
  1023.  
  1024.    if (IBM_chars)
  1025.       {
  1026.       while (len >= 8)
  1027.      {
  1028.      ip_write(line,8,fp) ;
  1029.      len -= 8 ;
  1030.      }
  1031.       if (len)
  1032.      ip_write(line,len,fp) ;
  1033.       }
  1034.    else
  1035.       {
  1036.       while (len >= 8)
  1037.      {
  1038.      ip_write("--------",8,fp) ;
  1039.      len -= 8 ;
  1040.      }
  1041.       if (len)
  1042.      ip_write("--------",len,fp) ;
  1043.       }
  1044. }
  1045.  
  1046. /***********************************************/
  1047.  
  1048. void HPPCL_put_line(fp,len)
  1049. IP_FILE *fp ;
  1050. int len ;
  1051. {
  1052.    ip_putlit(HPPCL_IBM_LN_A,fp) ;
  1053.    ip_puts(itoa((len * 25), num, 10),fp) ;
  1054.    ip_putlit(HPPCL_IBM_LN_B,fp) ;
  1055. }
  1056.  
  1057. /***********************************************/
  1058.  
  1059. void HPPCL_set_typeface(fp,typeface)
  1060. IP_FILE *fp ;
  1061. char *typeface ;
  1062. {
  1063.    ip_putlit(HPPCL_FONT_ON_A,fp) ;
  1064.    if (typeface)
  1065.       ip_puts(typeface,fp) ;
  1066.    else
  1067.       ip_putlit("8",fp) ;
  1068.    ip_putlit(HPPCL_FONT_ON_B,fp) ;
  1069. }
  1070.  
  1071. /***********************************************/
  1072.  
  1073. int is_keyword(s,keys,numkeys)
  1074. char *s ;
  1075. KEYWORDS *keys ;
  1076. unsigned int numkeys ;
  1077. {
  1078.    register int cmp ;
  1079.    register unsigned int i ;
  1080.    KEYWORDS *currkey ;
  1081.    int firstchar = *s ;
  1082.  
  1083.    do {
  1084.       i = numkeys / 2 ;
  1085.       currkey = &keys[i] ;
  1086.       cmp = (firstchar - currkey->name[0]) ;
  1087.       if (cmp == 0)
  1088.          cmp = memcmp(s,currkey->name,currkey->length) ;
  1089.       if (cmp < 0)
  1090.      numkeys = i ;
  1091.       else if (cmp > 0)
  1092.      {
  1093.      keys = currkey+1 ;
  1094.      numkeys -= i+1 ;
  1095.      }
  1096.       else
  1097.      return TRUE ;
  1098.       } while (numkeys) ;
  1099.    return FALSE ;
  1100. }
  1101.  
  1102. /***********************************************/
  1103.  
  1104. void output_line(line,fp)
  1105. char *line ;
  1106. IP_FILE *fp ;
  1107. {
  1108.    if (*line)
  1109.       {
  1110.       int pos = 0 ;
  1111.       int len = strlen(line) ;
  1112.       
  1113.       indent_line(fp) ;
  1114.       if (boldface)
  1115.      {
  1116.      if (start_of_entry(line) || start_of_table(line))
  1117.         {
  1118.         if (printer_bold)
  1119.            {
  1120.            ip_putcstr(&printer->bold_on,fp) ;
  1121.            ip_write(line,len,fp) ;
  1122.            ip_putcstr(&printer->bold_off,fp) ;
  1123.            newline(fp) ;
  1124.            return ;
  1125.            }
  1126.         else
  1127.            {
  1128.            ip_write(line,len,fp) ;
  1129.            ip_putc('\r',fp) ;
  1130.            indent_line(fp) ;
  1131.            }
  1132.         }
  1133.      else if (section_start(line))
  1134.         {
  1135.         pos = (char *)memchr(line,':',len) - line ;
  1136.         if (printer_bold)
  1137.            {
  1138.            ip_putcstr(&printer->bold_on,fp) ;
  1139.            ip_write(line,pos,fp) ;
  1140.            ip_putcstr(&printer->bold_off,fp) ;
  1141.            line += pos ;       /* adjust because no longer at left edge */
  1142.            len -= pos ;
  1143.            }
  1144.         else
  1145.            {
  1146.            ip_write(line,pos,fp) ;
  1147.            ip_putc('\r',fp) ;
  1148.            indent_line(fp) ;
  1149.            }
  1150.         }
  1151.      } /* boldface */
  1152.       if (indent & 7)  /* indenting by other than a multiple of 8 ? */
  1153.      {
  1154.      while (*line)
  1155.         {
  1156.         if (*line == '\t')
  1157.            {
  1158.            ip_write("        ",8-(pos&7),fp) ;
  1159.            pos = 0 ;   /* absolute column doesn't matter, only mod 8 */
  1160.            }
  1161.         else
  1162.            {
  1163.            ip_putc(*line,fp) ;
  1164.            pos++ ;
  1165.            }
  1166.         line++ ;
  1167.         }
  1168.      }
  1169.       else
  1170.      ip_write(line,len,fp) ;
  1171.       }
  1172.    newline(fp) ;
  1173. }
  1174.  
  1175. /***********************************************/
  1176.  
  1177. void get_raw_line(buf)
  1178. char *buf ;
  1179. {
  1180.    IP_FILE *in ;
  1181.    
  1182.    buf[0] = '\0' ;
  1183.    if (out_of_files)
  1184.       return ;
  1185.    current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1186.    if (current_line_offset == (unsigned long)-1)
  1187.       if (multi_file)
  1188.      {
  1189.      offset_adjust += lseek(infile->fd,0L,SEEK_END) ;
  1190.      input_file[input_file_namelen-1]++ ;
  1191.      ip_close(infile) ;
  1192.      if ((in = ip_open_read(input_file,infile_buf,sizeof(infile_buf)))
  1193.            != NULL)
  1194.         {
  1195.         infile = in ;
  1196.         current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1197.         }
  1198.      else
  1199.         {
  1200.         out_of_files = TRUE ;
  1201.         return ;
  1202.         }
  1203.      }
  1204.       else
  1205.      out_of_files = TRUE ;
  1206. }
  1207.  
  1208. /***********************************************/
  1209.  
  1210. int unwanted_section(buf)
  1211. char *buf ;
  1212. {
  1213.    int found ;
  1214.    char str[MAXLINE] ;
  1215.    FILT_LIST *p ;
  1216.  
  1217.    if (start_of_entry(buf)) /* is it an interrupt entry? */
  1218.       {
  1219.       strcpy(str,buf) ;
  1220.       (void) strupr(str) ;
  1221.       /* section is unwanted if *any* exclude string matches */
  1222.       for (p = excludes ; p ; p = p->next)
  1223.      {
  1224.      if (p->str && strstr(str, p->str) != NULL)
  1225.         return TRUE ;
  1226.      }
  1227.       /* if still wanted, set to TRUE if *no* include string matches */
  1228.       found = FALSE ;
  1229.       for (p = includes ; p ; p = p->next)
  1230.      {
  1231.      if (p->str && strstr(str, p->str) != NULL)
  1232.         {
  1233.         found = TRUE ;
  1234.         break ;
  1235.         }
  1236.      }
  1237.       if (!found)
  1238.      return TRUE ;
  1239.       }
  1240.    return FALSE ;
  1241. }
  1242.  
  1243. /***********************************************/
  1244.  
  1245. void get_line(buf)
  1246. char *buf ;
  1247. {
  1248.    static char next_line[MAXLINE] ;
  1249.    static int readahead = FALSE ;
  1250.  
  1251.    /* get the next line from the file, skipping unwanted entries */
  1252.    if (readahead)
  1253.       {
  1254.       strcpy(buf,next_line) ;
  1255.       readahead = FALSE ;
  1256.       }
  1257.    else
  1258.       {
  1259.       do {
  1260.      get_raw_line(buf) ;
  1261.      } while (!include_index_lines && index_line(buf)) ;
  1262.       if (section_file_start(buf))
  1263.      do {
  1264.         get_raw_line(buf) ;
  1265.         } while (buf[0] && !divider_line(buf)) ;
  1266.       if (do_filter)
  1267.      {
  1268.      /* if we read a divider line while filtering, we have to look ahead */
  1269.      strcpy(next_line,buf);
  1270.      while (next_line[0] && divider_line(next_line))
  1271.         {
  1272.         strcpy(buf,next_line) ; /* we may be returning the divider */
  1273.         get_raw_line(next_line) ;
  1274.         if (unwanted_section(next_line))
  1275.            {
  1276.            while (!divider_line(next_line))
  1277.           get_raw_line(next_line) ;
  1278.            }
  1279.         else /* section is wanted, so return divider and then next line */
  1280.            readahead = TRUE ;
  1281.         }
  1282.      }
  1283.       }
  1284. }
  1285.  
  1286. /***********************************************/
  1287.  
  1288. void fill_buffer(lines,lines_per_page)
  1289. int lines, lines_per_page ;
  1290. {
  1291.    int i ;
  1292.  
  1293.    /* copy remainder, if any, from last page to top of current page */
  1294.    if (lines)
  1295.       for (i = lines ; i < lines_per_page ; i++)
  1296.      {
  1297.      strcpy(buffer[i-lines], buffer[i]) ;
  1298.      line_offsets[i-lines] = line_offsets[i] ;
  1299.      }
  1300.    else
  1301.       lines = lines_per_page ;
  1302.    for (i = lines_per_page - lines ; i < lines_per_page ; i++)
  1303.       {
  1304.       get_line(buffer[i]) ;
  1305.       line_offsets[i] = current_line_offset + offset_adjust ;
  1306.       }
  1307. }
  1308.  
  1309. /***********************************************/
  1310.  
  1311. int find_page_break(lines)
  1312. int lines ;
  1313. {
  1314.    int i ;
  1315.    char *buf ;
  1316.  
  1317.    for (i = 0 ; i < widow_length ; i++)
  1318.       {
  1319.       buf = buffer[lines-i-1] ;
  1320.       if (buf[0] == '\0' || divider_line(buf))
  1321.      return lines - i ;
  1322.       else if (section_start(buf))
  1323.      return lines - i - 1 ;
  1324.       }
  1325.    return lines ;
  1326. }
  1327.  
  1328. /***********************************************/
  1329.  
  1330. int summarize(line, pages_printed)
  1331. int line, pages_printed ;
  1332. {
  1333.    char *s, reg ;
  1334.    int i ;
  1335.    int max_descrip ;
  1336.    int len, numlen ;
  1337.  
  1338.    s = buffer[line] ;
  1339.    if (start_of_entry(s))
  1340.       {
  1341.       memcpy(summary_line," -- -- -- ",10) ;
  1342.       summary_line[1] = s[4] ;     /* output interrupt number */
  1343.       summary_line[2] = s[5] ;
  1344.       len = 4 ;
  1345.       s = buffer[line+1] ;
  1346.       while (*s && isspace(*s))
  1347.      s++ ;
  1348.       if (*s == 'A')
  1349.      {
  1350.      reg = s[1] ;
  1351.      while (*s && *s != '=')
  1352.         s++ ;
  1353.      s++ ;        /* skip the equal sign */
  1354.      while (*s && isspace(*s))
  1355.         s++ ;    /* skip the space between equal sign and number */
  1356.      if (isxdigit(*s) && isxdigit(s[1]))
  1357.         {
  1358.         if (reg == 'L')
  1359.            len += 3 ;
  1360.         summary_line[len++] = *s++ ;
  1361.         summary_line[len++] = *s++ ;
  1362.         if (reg == 'X')
  1363.            {
  1364.            len++ ;
  1365.            summary_line[len++] = *s++ ;
  1366.            summary_line[len] = *s ;
  1367.            }
  1368.         }
  1369.      }
  1370.       len = 10 ;
  1371.       if (page_numbers)
  1372.      {
  1373.      itoa(pages_printed,num,10) ;
  1374.      numlen = strlen(num) ;
  1375.      for (i = numlen ; i < 3 ; i++)
  1376.         summary_line[len++] = ' ' ;
  1377.      memcpy(summary_line+len,num,numlen) ;
  1378.      len += numlen ;
  1379.      summary_line[len++] = ' ' ;
  1380.      }
  1381.       s = buffer[line] + 7 ;    /* find function description */
  1382.       if (*s && *s != '-')    /* does the heading contain flags? */
  1383.      {
  1384.      while (*s && !isspace(*s))
  1385.         summary_line[len++] = *s++ ;
  1386.      summary_line[len++] = '>' ;
  1387.      summary_line[len++] = ' ' ;
  1388.      while (*s && *s != '-')
  1389.         s++ ;
  1390.      }
  1391.       while (*s && !isspace(*s))
  1392.      s++ ;
  1393.       while (*s && isspace(*s))
  1394.      s++ ;
  1395.       max_descrip = (page_width > sizeof(summary_line)-1) ? 
  1396.                    sizeof(summary_line)-1 : page_width ;
  1397.       while (len < max_descrip && *s)
  1398.      summary_line[len++] = *s++ ;
  1399.       summary_line[len] = '\0' ;
  1400.       summary_line_len = len ;
  1401.       return 1 ;
  1402.       }
  1403.    else
  1404.       return 0 ;
  1405. }
  1406.  
  1407. /***********************************************/
  1408.  
  1409. void start_format(line)
  1410. char *line ;
  1411. {
  1412.    indent_line(formats) ;
  1413.    (*printer->put_line)(formats,79) ;
  1414.    newline(formats) ;
  1415.    indent_line(formats) ;
  1416.    ip_puts(summary_line,formats) ;
  1417.    newline(formats) ;
  1418.    indent_line(formats) ;
  1419.    ip_putc('\t',formats) ;
  1420.    ip_puts(line+10,formats) ;
  1421.    newline(formats) ;
  1422.    echo_format = TRUE ;
  1423. }
  1424.  
  1425. /***********************************************/
  1426.  
  1427. void show_offset(line,fp)
  1428. int line ;
  1429. IP_FILE *fp ;
  1430. {
  1431.    char offset_string[12] ;
  1432.    int len ;
  1433.    
  1434.    ultoa(line_offsets[line],offset_string,16) ;
  1435.    len = strlen(offset_string) ;
  1436.    ip_write("00000000",8-len,fp) ;
  1437.    ip_write(offset_string,len,fp) ;
  1438. }
  1439.  
  1440. /***********************************************/
  1441.  
  1442. void add_table(i)
  1443. int i ;
  1444. {
  1445.    char firstchar ;
  1446.    char num[6] ;
  1447.    char *end ;
  1448.    int len ;
  1449.    int summary_width ;
  1450.    char found = FALSE ;
  1451.    
  1452.    prev_table++ ;
  1453.    firstchar = buffer[i][0] ;
  1454.    if (firstchar == 'C' || firstchar == 'V')  /* Call.. or Values... ? */
  1455.       {
  1456.       if (i > 0 && buffer[i-1][0] == '(')
  1457.      {
  1458.      memcpy(num,buffer[i-1]+7,4) ;
  1459.      num[4] = '\0' ;
  1460.      len = 4 ;
  1461.      found = TRUE ;
  1462.      }
  1463.       }
  1464.    else if (firstchar == 'B' || firstchar == 'F') /* Bitfields.. or Format..? */
  1465.       {
  1466.       end = strrchr(buffer[i+1]+7,')') ;   /* rule out Bit(s) as only match */
  1467.       if (end)
  1468.      {
  1469.      memcpy(num,end-4,4) ;
  1470.      num[4] = '\0' ;
  1471.      len = 4 ;
  1472.      found = TRUE ;
  1473.      }
  1474.       }
  1475.    if (!found)
  1476.       {
  1477.       itoa(prev_table,num,10) ;
  1478.       len = strlen(num) ;
  1479.       }
  1480.    indent_line(tables) ;
  1481.    if (show_offsets)
  1482.       show_offset(i,tables) ;
  1483.    ip_write(" 0000",5-len,tables) ;
  1484.    ip_write(num,len,tables);
  1485.    if (page_numbers)
  1486.       {
  1487.       summary_width = 13 ;
  1488.       while (summary_line[summary_width] != ' ')
  1489.      summary_width++ ;
  1490.       summary_width++ ;    /* include the blank we found */
  1491.       }
  1492.    else
  1493.       summary_width = 10 ;
  1494.    ip_write(summary_line,summary_width,tables) ;
  1495.    len = strlen(buffer[i])-1 ;
  1496.    if (len > page_width - summary_width - 5)
  1497.       len = page_width - summary_width - 5 ;
  1498.    ip_write(buffer[i],len,tables) ;
  1499.    newline(tables) ;
  1500. }
  1501.  
  1502. /***********************************************/
  1503.  
  1504. int make_description(desc,line)
  1505. char *desc ;
  1506. int line ;
  1507. {
  1508.    char *start = desc ;
  1509.    
  1510.    summarize(line,pages_printed) ;
  1511.    memcpy(desc,"INT ", 4) ;
  1512.    desc += 4 ;
  1513.    *desc++ = summary_line[1] ;
  1514.    *desc++ = summary_line[2] ;
  1515.    if (summary_line[4] != '-')
  1516.       {
  1517.       memcpy(desc,", AH=", 5) ;
  1518.       desc += 5 ;
  1519.       *desc++ = summary_line[4] ;
  1520.       *desc++ = summary_line[5] ;
  1521.       }
  1522.    if (summary_line[7] != '-')
  1523.       {
  1524.       memcpy(desc,", AL=", 5) ;
  1525.       desc += 5 ;
  1526.       *desc++ = summary_line[7] ;
  1527.       *desc++ = summary_line[8] ;
  1528.       }
  1529.    *desc = '\0' ;
  1530.    return (desc-start)+1 ;
  1531. }
  1532.  
  1533. /***********************************************/
  1534.  
  1535. char *determine_heading(last)
  1536. int last ;
  1537. {
  1538.    int i ;
  1539.    static char heading[MAXLINE] ;
  1540.    char save[25] ;
  1541.    char num[10] ;
  1542.  
  1543.    /* ugly hack to keep the combination of -H and -T from showing wrong page */
  1544.    /* numbers for tables--copy last summary line from previous page to safe */
  1545.    /* place before processing current page, then restore it */
  1546.    memcpy(save,summary_line,sizeof(save)) ;
  1547.    if (start_of_entry(buffer[0]))
  1548.       {
  1549.       header_first.len = make_description(header_first.desc,0) ;
  1550.       header_first.part = 1 ;
  1551.       header_first.first_on_page = TRUE ;
  1552.       }
  1553.    else if (header_last.part == 0)  /* very first entry? */
  1554.       {
  1555.       for (i = 0 ; i < last ; i++)
  1556.      if (start_of_entry(buffer[i]))
  1557.         {
  1558.         header_first.len = make_description(header_first.desc,i) ;
  1559.         header_first.part = 1 ;
  1560.         header_first.first_on_page = TRUE ;
  1561.         break ;
  1562.         }
  1563.       }
  1564.    else
  1565.       {
  1566.       header_first.len = header_last.len ;
  1567.       memcpy(header_first.desc,header_last.desc,header_last.len) ;
  1568.       header_first.part = header_last.part + 1 ;
  1569.       header_first.first_on_page = FALSE ;
  1570.       }
  1571.    /* assume entry spans entire page */
  1572.    header_last.len = header_first.len ;
  1573.    memcpy(header_last.desc,header_first.desc,header_first.len) ;
  1574.    header_last.part = header_first.part ;
  1575.    header_last.first_on_page = header_first.first_on_page ;
  1576.    /* find last entry on page */
  1577.    if (header_first.part > 0)
  1578.       {
  1579.       for (i = last-1 ; i > 0 ; i--)
  1580.      if (start_of_entry(buffer[i]))
  1581.         {
  1582.         header_last.len = make_description(header_last.desc,i) ;
  1583.         header_last.part = 1 ;
  1584.         header_last.first_on_page = FALSE ;
  1585.         break ;
  1586.         }
  1587.       memcpy(heading,header_first.desc,header_first.len) ;
  1588.       if (header_first.part > 1)
  1589.      {
  1590.      strcat(heading," (Part ") ;
  1591.      strcat(heading,itoa(header_first.part,num,10)) ;
  1592.      strcat(heading,")") ;
  1593.      }
  1594.       if (memcmp(header_first.desc,header_last.desc,header_last.len) != 0 ||
  1595.       header_first.part != header_last.part)
  1596.      {
  1597.      strcat(heading," to ") ;
  1598.      strcat(heading,header_last.desc) ;
  1599.      if (header_last.part > 1)
  1600.         {
  1601.         strcat(heading," (Part ") ;
  1602.         strcat(heading,itoa(header_last.part,num,10)) ;
  1603.         strcat(heading,")") ;
  1604.         }
  1605.      }
  1606.       memcpy(summary_line,save,sizeof(save)) ;
  1607.       return heading ; 
  1608.       }
  1609.    else /* no headings yet */
  1610.       {
  1611.       memcpy(summary_line,save,sizeof(save)) ;
  1612.       return NULL ;
  1613.       }
  1614. }
  1615.  
  1616. /***********************************************/
  1617.  
  1618. void print_buffer(last,body_lines,lines_per_page,total_lines,use_FF)
  1619. int last, body_lines, lines_per_page, total_lines ;
  1620. int use_FF ;
  1621. {
  1622.    int i, len ;
  1623.    int headpos ;
  1624.    int print_this_page = (pages_printed>=first_page && pages_printed<=last_page);
  1625.    
  1626.    pages_printed++ ;
  1627.    if (do_headers)
  1628.       {
  1629.       char *heading ;
  1630.       
  1631.       if ((heading = determine_heading(last)) != NULL)
  1632.      {
  1633.      if (print_this_page)
  1634.         {
  1635.         len = strlen(heading) ;
  1636.         headpos = 40-len/2 ;
  1637.         indent_to(headpos,outfile) ;
  1638.         if (boldface)
  1639.            {
  1640.            if (printer_bold)
  1641.           {
  1642.           ip_putcstr(&printer->bold_on,outfile) ;
  1643.           ip_write(heading,len,outfile) ;
  1644.           ip_putcstr(&printer->bold_off,outfile) ;
  1645.           }
  1646.            else
  1647.           {
  1648.           ip_write(heading,len,outfile) ;
  1649.           ip_putc('\r',outfile) ;
  1650.           indent_to(headpos,outfile) ;
  1651.           ip_write(heading,len,outfile) ;
  1652.           }
  1653.            }
  1654.         else
  1655.            ip_write(heading,len,outfile) ;
  1656.         }
  1657.      }
  1658.       newline(outfile) ;
  1659.       newline(outfile) ;
  1660.       }
  1661.    for (i = 0 ; i < last ; i++)
  1662.       {
  1663.       if (print_this_page)
  1664.      {
  1665.      char *line = buffer[i] ;
  1666.      if (*line)
  1667.         {
  1668.         if (!keep_divider_lines && divider_line(line))
  1669.            {
  1670.            indent_line(outfile) ;
  1671.            (*printer->put_line)(outfile,79) ;
  1672.            newline(outfile) ;
  1673.            echo_format = FALSE ;
  1674.            }
  1675.         else
  1676.            {
  1677.            output_line(line, outfile) ;
  1678.            if (echo_format)
  1679.           output_line(line,formats) ;
  1680.            }
  1681.         }
  1682.      else
  1683.         {
  1684.         newline(outfile) ;
  1685.         echo_format = FALSE ;
  1686.         }
  1687.      }
  1688.       /* need summary lines if doing summary, formats, or table index */
  1689.       if (need_summary)
  1690.      {
  1691.      if (summarize(i,pages_printed) && do_summary && summary)
  1692.         {
  1693.         if (show_offsets)
  1694.            show_offset(i,summary) ;
  1695.         ip_write(summary_line,summary_line_len,summary) ;
  1696.         newline(summary) ;
  1697.         }
  1698.      if (do_formats && memcmp(buffer[i],"Format ",7) == 0)
  1699.         start_format(buffer[i]) ;
  1700.      if (do_tables && start_of_table(buffer[i]))
  1701.         add_table(i) ;
  1702.      }
  1703.       }
  1704.    if (print_this_page)
  1705.       {
  1706.       if (page_numbers)
  1707.      {
  1708.      for (i = last ; i <= body_lines ; i++)
  1709.         newline(outfile) ;
  1710.      itoa(pages_printed, num, 10) ;
  1711.      i = strlen(num) ;
  1712.      if (!duplex)
  1713.         indent_to(38-i/2,outfile) ;
  1714.      else if (pages_printed & 1)        /* odd-numbered page? */
  1715.         indent_to(75-i/2,outfile) ;
  1716.      else
  1717.         indent_to(2,outfile) ;
  1718.      ip_putlit("- ", outfile) ;
  1719.      ip_write(num, i, outfile) ;
  1720.      ip_putlit(" -", outfile) ;
  1721.      newline(outfile) ;
  1722.      }
  1723.       if (use_FF)
  1724.      ip_putc('\f',outfile) ;
  1725.       else
  1726.      for (i = page_numbers?lines_per_page:last ; i<total_lines ; i++)
  1727.         newline(outfile) ;
  1728.       if (duplex)
  1729.      {
  1730.      if (pages_printed & 1)           /* next page even or odd? */
  1731.         ip_putcstr(&printer->marginl, outfile) ;    /* even page */
  1732.      else
  1733.         ip_putcstr(&printer->marginr, outfile) ;    /* odd page */
  1734.      }
  1735.       }
  1736. }
  1737.  
  1738. /***********************************************/
  1739.  
  1740. void display_printers()
  1741. {
  1742.    int i ;
  1743.    
  1744.    ip_putlit("Valid printer names are:",err) ;
  1745.    newline(err) ;
  1746.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1747.       {
  1748.       ip_putc('\t',err) ;
  1749.       ip_puts(printers[i].name,err) ;
  1750.       newline(err) ;
  1751.       }
  1752.    ip_putlit("When entering the printer name, use either a dash or an",err) ;
  1753.    newline(err) ;
  1754.    ip_putlit("underscore in place of blanks.  Case is ignored, and the",err) ;
  1755.    newline(err) ;
  1756.    ip_putlit("name may be abbreviated to the shortest unique prefix.",err) ;
  1757.    newline(err) ;
  1758.    exit(1) ;
  1759. }
  1760.  
  1761. /***********************************************/
  1762.  
  1763. void select_printer(name)
  1764. char *name ;
  1765. {
  1766.    int i, len, prt = -1 ;
  1767.    
  1768.    len = strlen(name) ;
  1769.    for (i = 0 ; i < len ; i++)        /* convert dashes and underscores to blanks */
  1770.       if (name[i] == '-' || name[i] == '_')
  1771.      name[i] = ' ' ;
  1772.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1773.       if (strnicmp(name,printers[i].name,len) == 0)
  1774.      if (prt == -1)
  1775.         prt = i ;
  1776.      else
  1777.         fatal("Ambiguous printer name!  Use -P? to list printers.") ;
  1778.    if (prt == -1)
  1779.       fatal("Unknown printer name!  Use -P? to list printers.") ;
  1780.    else
  1781.       printer = &printers[prt] ;
  1782. }
  1783.  
  1784. /***********************************************/
  1785.  
  1786. FILT_LIST *add_filter_info(list,str)
  1787. FILT_LIST *list ;
  1788. char *str ;
  1789. {
  1790.    FILT_LIST *newfilt ;
  1791.    int len = strlen(str)+1 ;
  1792.    
  1793.    if ((newfilt = (FILT_LIST *)malloc(sizeof(struct filter_list)+len))
  1794.       != NULL)
  1795.       {
  1796.       newfilt->next = list ;
  1797.       memcpy(newfilt->str,str,len) ;
  1798.       strupr(newfilt->str) ;
  1799.       }
  1800.    else
  1801.       fatal("out of memory") ;
  1802.    return newfilt ;
  1803. }
  1804.  
  1805. /***********************************************/
  1806.  
  1807. void build_filter_lists(file)
  1808. char *file ;
  1809. {
  1810.    IP_FILE *fp ;
  1811.    char buf[MAXLINE] ;
  1812.    int len ;
  1813.    long result ;
  1814.  
  1815.    if ((fp = ip_open_read(file,filter_buf,sizeof(filter_buf))) == NULL)
  1816.       {
  1817.       warning("unable to open filtering file, will print entire list.") ;
  1818.       do_filter = FALSE ;
  1819.       }
  1820.    else /* OK, file is open, so start reading */
  1821.       {
  1822.       do {
  1823.      buf[0] = '\0' ;
  1824.      result = ip_fgets(buf, sizeof(buf), fp) ;
  1825.      len = strlen(buf) ;
  1826.      if (len > 1)
  1827.         {
  1828.         switch (buf[0])
  1829.            {
  1830.            case '+':
  1831.           includes = add_filter_info(includes,buf+1) ;
  1832.           break ;
  1833.            case '-':
  1834.           excludes = add_filter_info(excludes,buf+1) ;
  1835.           break ;
  1836.            case '#':        /* comment lines */
  1837.            default:
  1838.           break ;
  1839.            }
  1840.         }
  1841.      } while (result != -1) ;
  1842.       ip_close(fp) ;
  1843.       do_filter = TRUE ;
  1844.       }
  1845. }
  1846.  
  1847. /***********************************************/
  1848.  
  1849. void write_summary_header(fp,title,show_offsets,show_table)
  1850. IP_FILE *fp ;
  1851. char *title ;
  1852. int show_offsets, show_table ;
  1853. {
  1854.    /* set up the printer */
  1855.    ip_putcstr(&printer->init1,fp) ;
  1856.    ip_putcstr(&printer->init2,fp) ;
  1857.    ip_putcstr(&printer->marginc,fp) ;
  1858.    /* now start writing the actual header */
  1859.    indent_to(show_offsets?8:0,fp) ;
  1860.    ip_putlit("\t\t\t\t",fp) ;
  1861.    ip_puts(title,fp) ;
  1862.    newline(fp) ;
  1863.    indent_to(show_offsets?8:0,fp) ;
  1864.    ip_putlit("\t\t\t\t",fp) ;
  1865.    (*printer->put_line)(fp,strlen(title)) ;
  1866.    newline(fp) ;
  1867.    newline(fp) ;
  1868.    indent_line(fp) ;
  1869.    if (show_offsets)
  1870.       ip_putlit("Offset  ", fp) ;
  1871.    if (show_table)
  1872.       ip_putlit("Tbl# ",fp) ;
  1873.    ip_putlit("INT AH AL", fp) ;
  1874.    if (page_numbers)
  1875.       ip_putlit(" Page", fp) ;
  1876.    ip_putlit("\t\t\tDescription", fp) ;
  1877.    newline(fp) ;
  1878.    indent_line(fp) ;
  1879.    (*printer->put_line)(fp,page_width+(show_offsets?8:0)) ;
  1880.    newline(fp) ;
  1881. }
  1882.  
  1883. /***********************************************/
  1884.  
  1885. static void reset_printer_and_close(fp)
  1886. IP_FILE *fp ;
  1887. {
  1888.    ip_putcstr(&printer->term1,fp) ;
  1889.    ip_putcstr(&printer->term2,fp) ;
  1890.    ip_close(fp) ;
  1891. }
  1892.  
  1893. /***********************************************/
  1894.  
  1895. int _Cdecl main(argc,argv)
  1896. int argc ;
  1897. char *argv[] ;
  1898. {
  1899.    int lines_per_page = -1 ;
  1900.    int total_lines = -1 ;
  1901.    int use_FF = TRUE ;
  1902.    int last_line ;
  1903.    int body_lines ;
  1904.    char *typeface = NULL ;
  1905.    char *summary_file = NULL ;
  1906.    char *table_file = NULL ;
  1907.    char *formats_file = NULL ;
  1908.    char *filter_file = NULL ;
  1909.    char *last_page_num ;
  1910.  
  1911.    err = ip_fdopen(2,stderr_buf,sizeof(stderr_buf),sizeof(stderr_buf),1) ;
  1912.    ip_putlit("INTPRINT v", err) ;
  1913.    ip_putlit(VERSION, err) ;
  1914.    ip_putlit(" by Ralf Brown and others.  Donated to the Public Domain.",err) ;
  1915.    newline(err) ;
  1916.    ip_flush(err) ;
  1917.    if (argc == 1 && isatty(0))
  1918.       usage() ;      /* give help if invoked with no args and keybd input */
  1919.    while (argc >= 2 && argv[1][0] == '-')
  1920.       {
  1921.       switch (argv[1][1])
  1922.      {
  1923.      case 'B':
  1924.         printer_bold = TRUE ;
  1925.         /* fall through to -b */
  1926.      case 'b':
  1927.         boldface = TRUE ;
  1928.         break ;
  1929.      case 'd':
  1930.         duplex = TRUE ;
  1931.         break ;
  1932.      case 'e':
  1933.         indent = 8 ;
  1934.         page_width = 87 ;  /* 96 - indent - 1 right margin */
  1935.         break ;
  1936.      case 'f':
  1937.         formats_file = argv[1]+2 ;
  1938.         break ;
  1939.      case 'F':
  1940.         filter_file = argv[1]+2 ;
  1941.         break ;
  1942.      case 'H':   /* page headers */
  1943.         do_headers = TRUE ;
  1944.         break ;
  1945.      case 'i':
  1946.         indent = atoi(argv[1]+2) ;
  1947.         break ;
  1948.      case 'I':
  1949.         IBM_chars = TRUE ;
  1950.         break ;
  1951.      case 'k':
  1952.         keep_divider_lines = TRUE ;
  1953.         break ;
  1954.      case 'l':
  1955.         lines_per_page = atoi(argv[1]+2) ;
  1956.         break ;
  1957.      case 'L':
  1958.         total_lines = atoi(argv[1]+2) ;
  1959.         break ;
  1960.      case 'm':
  1961.         multi_file = TRUE ;
  1962.         break ;
  1963.      case 'n':
  1964.         pages_printed = atoi(argv[1]+2) ;
  1965.         break ;
  1966.      case 'P':
  1967.         if (argv[1][2] == '?')
  1968.            display_printers() ;
  1969.         else
  1970.            select_printer(argv[1]+2) ;
  1971.         break ;
  1972.      case 'p':
  1973.         page_numbers = TRUE ;
  1974.         break ;
  1975.      case 'r':
  1976.         first_page = atoi(argv[1]+2) ;
  1977.         last_page_num = strchr(argv[1]+2, ':') ;
  1978.         last_page = last_page_num ? atoi(last_page_num+1) : 0 ;
  1979.         if (last_page == 0)
  1980.            last_page = ~0 ;
  1981.         break ;
  1982.      case 's':
  1983.         summary_file = argv[1]+2 ;
  1984.         break ;
  1985.      case 't':
  1986.         typeface = argv[1]+2 ;
  1987.         break ;
  1988.      case 'T':
  1989.         table_file = argv[1]+2 ;
  1990.         break ;
  1991.      case 'V':
  1992.         show_offsets = IBM_chars = TRUE ;
  1993.         break ;
  1994.      case 'w':
  1995.         widow_length = atoi(argv[1]+2) ;
  1996.         break ;
  1997.      case 'x':
  1998.         include_index_lines = TRUE ;
  1999.         break ;
  2000.      default:
  2001.         usage() ;
  2002.      }
  2003.       argv++ ;
  2004.       argc-- ;
  2005.       }
  2006.    if (printer == NULL)
  2007.       select_printer("default") ;
  2008.    /* apply any necessary overrides to parameters */
  2009.    if (printer->indent != -1)
  2010.       indent = printer->indent ;
  2011.    if (lines_per_page < 0)
  2012.       lines_per_page = printer->lines_per_page ;
  2013.    if (total_lines <= 0)
  2014.       total_lines = printer->page_length ;
  2015.    if (page_width <= 0)
  2016.       page_width = printer->page_width ;
  2017.    if (show_offsets && page_width < 80)
  2018.       page_width = 80 ;
  2019.    if (printer->flag)
  2020.       *(printer->flag) = TRUE ;
  2021.    if (cstrlen(&printer->bold_on) == 0)     /* control sequences for bold? */
  2022.       printer_bold = FALSE ;        /* if not, don't try to use them */
  2023.    /* build the indent string */
  2024.    if (indent)
  2025.       {
  2026.       char *t ;
  2027.       int ind = indent ;
  2028.  
  2029.       indent_len = indent/8 + indent%8 ;
  2030.       t = indent_string = (char *)malloc(indent_len+1) ;
  2031.       while (ind >= 8)
  2032.      {
  2033.      *t++ = '\t' ;
  2034.      ind -= 8 ;
  2035.      }
  2036.       while (ind > 0)
  2037.      {
  2038.      *t++ = ' ' ;
  2039.      ind-- ;
  2040.      }
  2041.       }
  2042.    /* open the summary file, if any */
  2043.    if (summary_file && *summary_file)
  2044.       if ((summary = ip_open_write(summary_file,!pages_printed,summary_buf,
  2045.                    sizeof(summary_buf)))
  2046.         != NULL)
  2047.      do_summary = TRUE ;
  2048.       else
  2049.      warning("unable to open summary file") ;
  2050.    /* open the table index file, if any */
  2051.    if (table_file && *table_file)
  2052.       if ((tables = ip_open_write(table_file,!pages_printed,tables_buf,
  2053.                   sizeof(tables_buf)))
  2054.         != NULL)
  2055.      do_tables = TRUE ;
  2056.       else
  2057.      warning("unable to open table index file") ;
  2058.    /* open the data formats file, if any */
  2059.    if (formats_file && *formats_file)
  2060.       if ((formats = ip_open_write(formats_file,!pages_printed,formats_buf,
  2061.                    sizeof(formats_buf)))
  2062.         != NULL)
  2063.      do_formats = TRUE ;
  2064.       else
  2065.      warning("unable to open formats file") ;
  2066.    need_summary = (do_summary || do_formats || do_tables) ;
  2067.    /* initialize filtering data, if specified */
  2068.    if (filter_file && *filter_file)
  2069.       build_filter_lists(filter_file) ;
  2070.    if (total_lines <= lines_per_page)
  2071.       {
  2072.       total_lines = lines_per_page ;
  2073.       use_FF = TRUE ;
  2074.       }
  2075.    else
  2076.       use_FF = FALSE ;
  2077.    if (argc == 2 || argc == 3)
  2078.       {
  2079.       input_file = argv[1] ;
  2080.       input_file_namelen = strlen(input_file) ;
  2081.       if ((infile = ip_open_read(input_file,infile_buf,sizeof(infile_buf))) == NULL)
  2082.      fatal("unable to open input file") ;
  2083.       if (argc == 3)
  2084.      {
  2085.      outfile = ip_open_write(argv[2],!pages_printed,outfile_buf,
  2086.                  sizeof(outfile_buf)) ;
  2087.      if (outfile == NULL)
  2088.         fatal("unable to open output file") ;
  2089.      }
  2090.       else
  2091.      outfile = ip_open_write("",0,outfile_buf,sizeof(outfile_buf)) ;
  2092.       }
  2093.    else
  2094.       usage() ;
  2095.    if (lines_per_page > MAXPAGE)
  2096.       {
  2097.       ip_putlit("Surely you jest!  I can't handle pages that long.",err) ;
  2098.       newline(err) ;
  2099.       newline(err) ;
  2100.       usage() ;
  2101.       }
  2102.    else if (lines_per_page == 0) /* infinite page? */
  2103.       {
  2104.       widow_length = 0 ;
  2105.       if (total_lines <= 0)
  2106.      total_lines = MAXPAGE ;
  2107.       lines_per_page = total_lines ;
  2108.       use_FF = do_headers = page_numbers = FALSE ;
  2109.       }
  2110.    else
  2111.       {
  2112.       if (lines_per_page < 20)
  2113.      {
  2114.      ip_putlit("Surely your printer can handle at least 20 lines per page!",
  2115.            err) ;
  2116.      newline(err) ;
  2117.      ip_putlit("Adjusting page length....",err) ;
  2118.      newline(err) ;
  2119.      lines_per_page = 20 ;
  2120.      }
  2121.       if (widow_length < 3 || widow_length > lines_per_page / 2)
  2122.      {
  2123.      ip_putlit("Widow lines (-w) must be set to at least 3 and at most one-half of the",err) ;
  2124.      newline(err) ;
  2125.      ip_putlit("page length.  Using default of 8 lines.",err) ;
  2126.      newline(err) ;
  2127.      widow_length = 8 ;
  2128.      }
  2129.       }
  2130.    /* set up the printer */
  2131.    ip_putcstr(&printer->init1,outfile) ;
  2132.    ip_putcstr(&printer->init2,outfile) ;
  2133.    if (printer->set_typeface)
  2134.       (*printer->set_typeface)(outfile,typeface) ;
  2135.    if (duplex)
  2136.       {
  2137.       ip_putcstr(&printer->duplex_on,outfile) ;
  2138.       if (pages_printed & 1)          /* next page odd or even? */
  2139.      ip_putcstr(&printer->marginl,outfile) ;    /* even */
  2140.       else
  2141.      ip_putcstr(&printer->marginr,outfile) ;    /* odd */
  2142.       }
  2143.    else
  2144.       ip_putcstr(&printer->marginc,outfile) ;    /* non-duplex, so center */
  2145.    /* start the auxiliary files if this is the first part processed */
  2146.    if (pages_printed == 0)
  2147.       {
  2148.       /* start the summary file */
  2149.       if (do_summary)
  2150.      write_summary_header(summary,"Interrupt Summary",show_offsets,FALSE) ;
  2151.       /* start the table index file */
  2152.       if (do_tables)
  2153.      write_summary_header(tables,"Table Summary",show_offsets,TRUE) ;
  2154.       /* start the data formats file */
  2155.       if (do_formats)
  2156.      write_summary_header(formats,"Data Structure Formats",FALSE,FALSE) ;
  2157.       }
  2158.    if (page_numbers)
  2159.       body_lines = lines_per_page - 2 ;
  2160.    else
  2161.       body_lines = lines_per_page ;
  2162.    if (do_headers)
  2163.       body_lines -= 2 ;
  2164.    last_line = 0 ;
  2165.    while (!out_of_files)
  2166.       {
  2167.       fill_buffer(last_line,body_lines) ;
  2168.       last_line = find_page_break(body_lines) ;
  2169.       print_buffer(last_line,body_lines,lines_per_page,total_lines,use_FF) ;
  2170.       }
  2171.    if (last_line < body_lines)
  2172.       {
  2173.       int i ;
  2174.       
  2175.       for (i = last_line ; i < body_lines ; i++)
  2176.      {
  2177.      strcpy(buffer[i-last_line], buffer[i]) ;
  2178.      line_offsets[i-last_line] = line_offsets[i] ;
  2179.      }
  2180.       print_buffer(body_lines-last_line,body_lines,lines_per_page,total_lines,
  2181.            use_FF) ;
  2182.       }
  2183.    ip_close(infile) ;
  2184.    /* reset the printer */
  2185.    reset_printer_and_close(outfile) ;
  2186.    ip_puts(itoa(pages_printed, num, 10), err) ;
  2187.    ip_putlit(" pages", err) ;
  2188.    if (do_summary)
  2189.       reset_printer_and_close(summary) ;
  2190.    if (do_tables)
  2191.       {
  2192.       ip_putlit(", ", err) ;
  2193.       ip_puts(itoa(prev_table, num, 10), err) ;
  2194.       ip_putlit(" tables", err) ;
  2195.       reset_printer_and_close(tables) ;
  2196.       }
  2197.    if (do_formats)
  2198.       reset_printer_and_close(formats) ;
  2199.    newline(err) ;
  2200.    ip_close(err) ;
  2201.    return 0 ;
  2202. }
  2203.